#include "stdafx.h"
#include "EntityDataStore.h"
#include "Entity.h"

#include "IComponent.h"
#include "MathUtils.h"

#include "BoundingBoxComponent.h"
#include "TransformComponent.h"

using namespace std;

namespace ZeEngine
{
    EntityDataStore::EntityDataStore()
    {
        reserve(1000);
        m_freeEntities.reserve(1000);
    }

    EntityDataStore::~EntityDataStore()
    {
        for (auto it = begin(); it != end(); ++it)
        {
            delete *it;
        }

        for (auto it = m_freeEntities.begin(); it != m_freeEntities.end(); ++it)
        {
            delete *it;
        }

        clear();
        m_freeEntities.clear();
    }

    Entity* EntityDataStore::GetNewEntity(const string& name)
    {
        Entity* pEntity = NULL;

        //Only create an entity if we cant find a free one!
        if (!m_freeEntities.empty())
        {
            pEntity = m_freeEntities.back();
            m_freeEntities.pop_back();

            //Get a fresh new entity
            pEntity->Clear(name);
        }
        else
        {
            pEntity = new Entity(name);
        }

        return pEntity;
    }

    void EntityDataStore::Remove(Entity* pEntity)
    {
        if (pEntity)
        {
            m_freeEntities.push_back(pEntity);
            at(pEntity->GetIndex()) = NULL;
        }
    }

    void EntityDataStore::Insert(Entity* pEntity)
    {
        if (pEntity)
        {
            if (pEntity->GetIndex() == -1)
            {
                pEntity->SetIndex(size());
            }

            if (static_cast<u32>(pEntity->GetIndex()) >= size())
            {
                push_back(pEntity);
            }
            else
            {
                at(pEntity->GetIndex()) = pEntity;
            }
        }
    }

    EntityContainer::iterator EntityDataStore::end()
    {
        return EntityContainer::end();
    }

    EntityContainer::iterator EntityDataStore::begin()
    {
        return EntityContainer::begin();
    }

	bool EntityDataStore::GetIntersectingEntities(const Vector2D<f32>& position, const Vector2D<f32>& dimension, vector<Entity*>& oEntities)
	{
        SDL_Rect a{ static_cast<int>(position.GetX()), static_cast<int>(position.GetY()), 
                    static_cast<int>(dimension.GetX()), static_cast<int>(dimension.GetY()) };

        int count = size();

		for each (Entity* pEntity in *this)
		{
			if (pEntity && pEntity->IsActive())
			{
				auto bbComponent = pEntity->GetComponent<BoundingBoxComponent>();
				auto transformComponent = pEntity->GetComponent<TransformComponent>();

				if (bbComponent && transformComponent)
				{
					SDL_Rect b;

                    b.w = static_cast<int>(bbComponent->GetDimension().GetX());
                    b.h = static_cast<int>(bbComponent->GetDimension().GetY());
                    b.x = static_cast<int>(transformComponent->GetPosition().GetX());
                    b.y = static_cast<int>(transformComponent->GetPosition().GetY());

					if (Utilities::RectangleCollisionTest(a, b))
					{
						oEntities.push_back(pEntity);
					}
				}
			}
		}

		return !oEntities.empty();
	}
	
	bool EntityDataStore::HasIntersectingEntities(const Vector2D<f32>& position, const Vector2D<f32>& dimension)
	{
        SDL_Rect a{ static_cast<int>(position.GetX()), static_cast<int>(position.GetY()), 
                    static_cast<int>(dimension.GetX()), static_cast<int>(dimension.GetY()) };

		for each (Entity* pEntity in *this)
		{
			if (pEntity && pEntity->IsActive())
			{	
				auto bbComponent = pEntity->GetComponent<BoundingBoxComponent>();
				auto transformComponent = pEntity->GetComponent<TransformComponent>();

				if (bbComponent && transformComponent)
				{
					SDL_Rect b;
                    b.w = static_cast<int>(bbComponent->GetDimension().GetX());
                    b.h = static_cast<int>(bbComponent->GetDimension().GetY());
                    b.x = static_cast<int>(transformComponent->GetPosition().GetX());
                    b.y = static_cast<int>(transformComponent->GetPosition().GetY());

					if (Utilities::RectangleCollisionTest(a, b))
					{
						return true;
					}
				}
			}
		}

		return false;
	}
}
